import axios from 'axios';
import * as THREE from 'three';
import { lngLatToMercator, getTexture } from './index';
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js';
export default class {
  config: any;
  points: any[];
  shapes: any[];
  list: any[];
  infos: any[];
  box: THREE.Box3;
  body: THREE.Mesh;
  group: THREE.Group;
  line: THREE.LineSegments;
  constructor(config) {
    this.points = [];
    this.shapes = [];
    this.infos = [];
    const depth = 10;
    const lineColor = 0xffffff;
    this.box = new THREE.Box3();
    this.group = new THREE.Group();
    this.config = { depth, lineColor, ...config };
  }
  async load() {
    const res = await axios.get(this.config.url);
    res.data.features.forEach(feature => {
      const { type, coordinates } = feature.geometry;
      const { center, centroid, name } = feature.properties;
      this.infos.push({ center, centroid, name });
      coordinates.forEach(arr => {
        if (type === 'Polygon') arr = [arr];
        arr.forEach(this.convaterPolygon.bind(this));
      });
    });
    this.init();
  }
  add(object) {
    this.group.add(object);
  }
  move(x, y) {
    this.group.translateX(x);
    this.group.translateY(y);
  }
  convaterPolygon(list) {
    this.shapes.push(this.createShape(list));
    this.points = this.points.concat(this.createPoints(list, this.config.depth + 1));
  }
  async init() {
    let line = this.createLine(this.points);
    this.box.setFromObject(line);
    const geometries = this.createGeometry(this.shapes);
    const material = await this.createBodyMaterial();
    const geometry = mergeGeometries(geometries, true);
    const body = new THREE.Mesh(geometry, material);
    const body2 = new THREE.Group();
    body2.name = 'body2';
    console.log(this.infos);
    geometries.forEach((i, index) => {
      const info = this.infos[index];
      console.log(info);
      const material2 = new THREE.MeshBasicMaterial({
        color: 0x00ff00,
        opacity: 0,
        transparent: true
      });
      const item = new THREE.Mesh(i, material2);
      body2.add(item);
    });
    this.group.add(body, body2, line);
  }
  createLine(points) {
    const material = new THREE.LineBasicMaterial({ color: this.config.lineColor });
    const geometry = new THREE.BufferGeometry().setFromPoints(points);
    return new THREE.LineSegments(geometry, material);
  }
  createGeometry(list) {
    const { max, min } = this.box;
    return list.map(shape => {
      const uvList: any = [];
      const geometry = new THREE.ExtrudeGeometry(shape, { depth: this.config.depth });
      const position = geometry.attributes.position.array;
      for (let i = 0; i < position.length; i += 3) {
        const x = (position[i] - min.x) / (max.x - min.x);
        const y = (position[i + 1] - min.y) / (max.y - min.y);
        uvList.push(x, y);
      }
      const uv = new THREE.BufferAttribute(new Float32Array(uvList), 2);
      geometry.attributes.uv = uv;
      return geometry;
    });
  }
  async createBodyMaterial() {
    const { map, normal } = this.config;
    const texture: any = await getTexture({ url: map, colorSpace: THREE.SRGBColorSpace });
    const normalMap: any = await getTexture({ url: normal.map });
    const normalScale = normal.scale;
    return new THREE.MeshPhongMaterial({ map: texture, normalMap, normalScale });
  }
  createPoints(list, z) {
    const points: any = [];
    for (let i = 0; i < list.length - 1; i++) {
      const a = lngLatToMercator(list[i]);
      const b = lngLatToMercator(list[i + 1]);
      points.push(new THREE.Vector3(a.x, a.y, z), new THREE.Vector3(b.x, b.y, z));
    }
    return points;
  }
  createShape(list) {
    const points: any = [];
    list.forEach(item => {
      const point = lngLatToMercator(item);
      points.push(new THREE.Vector2(point.x, point.y));
    });
    return new THREE.Shape(points);
  }
}
